In [1]:
from sklearn import model_selection, tree
import graphviz
import pandas as pd
import numpy as np
import re
import pydotplus
from IPython.display import Image
from sklearn import model_selection, metrics
import matplotlib.pyplot as plt
%matplotlib inline
In [2]:
data = pd.read_csv('german.data.txt', sep=' ', header=None)
data.head()
Out[2]:
Вытащим из описания названия признаков и значения категориальных переменных.
In [3]:
with open('german.doc') as f:
description = f.readlines()
properties_names = []
properties = {}
description = map(lambda s: s.strip(), description)
for i in xrange(len(description)):
if re.match('Attr?ibute \d+', description[i]):
i += 1
properties_names += [description[i]]
match = re.match('(A\d+) : (.*)', description[i])
if match:
properties[match.group(1)] = match.group(2)
properties_names += ['Give credit']
In [4]:
data.columns = properties_names
data.replace(properties, inplace=True)
print 'число признаков =', len(data.columns) - 1
data.head()
Out[4]:
Теперь закодируем категориальные признаки, чтобы передать датасет дереву.
In [5]:
data_encode = pd.get_dummies(data)
print 'Теперь число признаков =', len(data_encode.columns) - 1
data_encode.head()
Out[5]:
Так же сделаем приведем target к классам 0 - не давать кредит, 1 - давать.
In [6]:
data_encode[u'Give credit'] = data_encode[u'Give credit'].apply(lambda x: 0 if x == 2 else 1)
y = data_encode[u'Give credit']
X = data_encode.drop((u'Give credit'), axis=1)
In [7]:
print 'Доли классов'
print '{} объектов 1-го класса'.format((y==1).sum() * 1./len(y))
print '{} объектов 0-го класса'.format((y==0).sum() * 1./len(y))
Построим дерево, получающееся при ограничении глубины не больше 2.
In [8]:
classifier = tree.DecisionTreeClassifier(max_depth=2)
classifier.fit(X, y)
dot_data = tree.export_graphviz(classifier, out_file="tree3.out",
feature_names=X.columns,
class_names=['credit', 'no credit'],
filled=True, rounded=True,
special_characters=False)
graph = pydotplus.graphviz.graph_from_dot_file("tree3.out")
Image(graph.create_png())
Out[8]:
Сначала разбиваем по размеру доходов и наличию счета. Если доходы большие или счета нет, то, если других обязательств нет - выдаем, иначе нет. В противном случае выдаем краткосрочные кредиты (меньше 22.5 месяцев).
Без ограничения
In [9]:
classifier = tree.DecisionTreeClassifier()
classifier.fit(X, y)
dot_data = tree.export_graphviz(classifier, out_file="tree.out",
feature_names=X.columns,
class_names=['credit', 'no credit'],
filled=True, rounded=True,
special_characters=False)
graph = pydotplus.graphviz.graph_from_dot_file("tree.out")
Image(graph.create_png())
Out[9]:
Теперь посмотрим на зависимость качества от глубины.
In [10]:
depths = np.arange(1, 30)
scores = []
train_score = []
X_train, y_train, X_test, y_test = model_selection.train_test_split(X, y, test_size=0.3)
for depth in depths:
model = tree.DecisionTreeClassifier(max_depth=depth)
scores += [model_selection.cross_val_score(model, X, y, scoring='roc_auc').mean()]
model.fit(X, y)
train_score += [metrics.roc_auc_score(y, model.predict(X))]
In [11]:
plt.figure(figsize=(10, 6))
plt.title('ROC_AUC score(depth)')
plt.plot(depths, scores, label='cross val score')
plt.plot(depths, train_score, label='train score')
plt.grid(True)
plt.xlabel('depth')
plt.ylabel('score')
plt.legend(loc='best')
plt.show()
In [12]:
print 'best depth =', np.argmax(scores) + 1
Теперь посмотрим что будет, если работать с german-numeric, датасетом, в котором уже категориальные признаки закодированы.
In [13]:
with open('german_data-numeric.txt') as f:
numeric_data = [map(int, line.strip().split()) for line in f.readlines()]
for i, x in enumerate(numeric_data):
numeric_data[i] = np.array(x)
numeric_data = np.array(numeric_data)
numeric_data = pd.DataFrame(numeric_data)
In [14]:
numeric_data
Out[14]:
Приведем target переменную от 1/2 к 1/0.
In [15]:
y = numeric_data.iloc[:, -1].apply(lambda x: 1 if x == 1 else 0)
X = numeric_data.iloc[:, :-1]
In [16]:
print 'Доли классов'
print '{} объектов 1-го класса'.format((y==1).sum() * 1./len(y))
print '{} объектов 0-го класса'.format((y==0).sum() * 1./len(y))
Построим дерево, получающееся при ограничении глубины не больше 2.
In [17]:
classifier = tree.DecisionTreeClassifier(max_depth=2)
classifier.fit(X, y)
dot_data = tree.export_graphviz(classifier, out_file="tree3.out",
feature_names=X.columns,
class_names=['credit', 'no credit'],
filled=True, rounded=True,
special_characters=False)
graph = pydotplus.graphviz.graph_from_dot_file("tree3.out")
Image(graph.create_png())
Out[17]:
Сначала разбиваем по размеру доходов и наличию счета. Если доходы большие или счета нет, то, если других обязательств нет - выдаем, иначе нет. В противном случае выдаем краткосрочные кредиты (меньше 22.5 месяцев).
Без ограничения
In [18]:
classifier = tree.DecisionTreeClassifier()
classifier.fit(X, y)
dot_data = tree.export_graphviz(classifier, out_file="tree.out",
feature_names=X.columns,
class_names=['credit', 'no credit'],
filled=True, rounded=True,
special_characters=False)
graph = pydotplus.graphviz.graph_from_dot_file("tree.out")
Image(graph.create_png())
Out[18]:
Теперь посмотрим на зависимость качества от глубины.
In [19]:
depths = np.arange(1, 30)
scores = []
train_score = []
X_train, y_train, X_test, y_test = model_selection.train_test_split(X, y, test_size=0.3)
for depth in depths:
model = tree.DecisionTreeClassifier(max_depth=depth)
scores += [model_selection.cross_val_score(model, X, y, scoring='roc_auc').mean()]
model.fit(X, y)
train_score += [metrics.roc_auc_score(y, model.predict(X))]
In [20]:
plt.figure(figsize=(10, 6))
plt.title('ROC_AUC score(depth)')
plt.plot(depths, scores, label='cross val score')
plt.plot(depths, train_score, label='train score')
plt.grid(True)
plt.xlabel('depth')
plt.ylabel('score')
plt.legend(loc='best')
plt.show()
In [21]:
print 'best depth =', np.argmax(scores) + 1